﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.Collections;
using Microsoft.Win32;
using System.IO;
using System.Threading;
using System.Windows.Threading;
using System.ComponentModel;

namespace RSA_LQ
{
    /// <summary>
    /// RSAWindow.xaml 的交互逻辑
    /// </summary>
    public partial class RSAWindow : Window
    {
        private static Random rand = new Random(); //随机数种子
        private static int i_currentRadix = 10;

        private static BackgroundWorker bgWorkerGenP = null; //后台处理生成大素数P
        private static BackgroundWorker bgWorkerGenQ = null; //后台处理生成大素数Q



        public RSAWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 生成大素数P的后台线程
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GenerateP(object sender, DoWorkEventArgs e)
        {
            WorkerArgs wArgs = e.Argument as WorkerArgs;
            int bits = wArgs.Bits;
            
            BigInteger bi = BigInteger.genPseudoPrime(bits, 2000, rand);

            int radix = wArgs.Radix;

            Dispatcher.Invoke(DispatcherPriority.Normal, 
                (ThreadStart)delegate
                {
                    textBox_P.Text = bi.ToString(radix);
                }
            );
        }
        /// <summary>
        /// 后台线程结束所做的操作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GenerateComplete(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                MessageBox.Show("用户取消生成", "提示", MessageBoxButton.OK);
            }
            else if (e.Error != null)
            {
                MessageBox.Show("出错", "错误", MessageBoxButton.OK);
            }
            else
            {
                //MessageBox.Show("生成成功", "提示", MessageBoxButton.OK);
            }
        }

        /// <summary>
        /// 产生素数p
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_GenerateP_Click(object sender, RoutedEventArgs e)
        {
            if (bgWorkerGenP != null)
            {
                if (bgWorkerGenP.IsBusy)
                {
                    MessageBox.Show("当前正在生成，请等待前面的生成结束方可再次生成", "提示", MessageBoxButton.OK);
                    return;
                }
            }
            textBox_P.Text = "正在生成大素数，请稍候...";

            bgWorkerGenP = new BackgroundWorker(); //后台处理生成大素数
            bgWorkerGenP.WorkerReportsProgress = true;
            bgWorkerGenP.WorkerSupportsCancellation = true;
            bgWorkerGenP.DoWork += new DoWorkEventHandler(GenerateP);
            bgWorkerGenP.RunWorkerCompleted += new RunWorkerCompletedEventHandler(GenerateComplete);

            int bits = Convert.ToInt32(textBox_Bits.Text.Trim());
            int radix = Convert.ToInt32(comboBox_Radix.SelectionBoxItem.ToString());
            WorkerArgs wArgs = new WorkerArgs(bits, radix);

            bgWorkerGenP.RunWorkerAsync(wArgs); //异步执行程序，wArgs传递进去
        }


        /// <summary>
        /// 生成大素数Q的后台线程
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GenerateQ(object sender, DoWorkEventArgs e)
        {
            WorkerArgs wArgs = e.Argument as WorkerArgs;
            int bits = wArgs.Bits;

            BigInteger bi = BigInteger.genPseudoPrime(bits, 2000, rand);

            int radix = wArgs.Radix;

            Dispatcher.Invoke(DispatcherPriority.Normal, 
                (ThreadStart)delegate
                {
                    textBox_Q.Text = bi.ToString(radix);
                }
            );
        }

        /// <summary>
        /// 产生素数q
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_GenerateQ_Click(object sender, RoutedEventArgs e)
        {
            if (bgWorkerGenQ != null)
            {
                if (bgWorkerGenQ.IsBusy)
                {
                    bgWorkerGenQ.CancelAsync();
                    MessageBox.Show("当前正在生成，请等待前面的生成结束方可再次生成", "提示", MessageBoxButton.OK);
                    return;
                }
            }

            textBox_Q.Text = "正在生成大素数，请稍候...";

            bgWorkerGenQ = new BackgroundWorker(); //后台处理生成大素数
            bgWorkerGenQ.WorkerReportsProgress = true;
            bgWorkerGenQ.WorkerSupportsCancellation = true;
            bgWorkerGenQ.DoWork += new DoWorkEventHandler(GenerateQ);
            bgWorkerGenQ.RunWorkerCompleted += new RunWorkerCompletedEventHandler(GenerateComplete);

            int bits = Convert.ToInt32(textBox_Bits.Text.Trim());
            int radix = Convert.ToInt32(comboBox_Radix.SelectionBoxItem.ToString());
            WorkerArgs wArgs = new WorkerArgs(bits, radix);

            //异步执行程序，wArgs作为参数传递进去
            //在DoWork对应的事件处理函数中用DoWorkEventArgs解出参数
            bgWorkerGenQ.RunWorkerAsync(wArgs); 
        }


        /// <summary>
        /// 验证是否有不可接受的字符
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private bool ValidateInputString(string str)
        {
            string smallStr = str.ToUpper();
            int radix = Convert.ToInt32(comboBox_Radix.SelectionBoxItem.ToString());

            if (radix == 10)
            {
                foreach (char item in smallStr)
                {
                    if (item >= '0' && item <= '9')
                    {
                    }
                    else
                    {
                        return false;
                    }
                }

            }
            else if (radix == 16)
            {
                foreach (char item in smallStr.ToCharArray())
                {
                    if ((item >= '0' && item <= '9') || (item >= 'A' && item <= 'F'))
                    {
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        /// <summary>
        /// 获取密钥
        /// N = p * q;
        /// NN = (p - 1) * (q - 1)
        /// E 范围为 （1, NN)  且gcd(NN, e) = 1)
        /// d * e = 1 (mod NN)， 即(d * e) mod NN = 1;
        /// 公钥为{e, n}，私钥为{d, n}
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_GenerateKey_Click(object sender, RoutedEventArgs e)
        {
            if (bgWorkerGenP != null)
            {
                if (bgWorkerGenP.IsBusy)
                {
                    MessageBox.Show("后台正在生成素数，请等待生成操作完成", "提示", MessageBoxButton.OK);
                    return;
                }
            }
            if (bgWorkerGenQ != null)
            {
                if (bgWorkerGenQ.IsBusy)
                {
                    MessageBox.Show("后台正在生成素数，请等待生成操作完成", "提示", MessageBoxButton.OK);
                    return;
                }
            }

            int radix = Convert.ToInt32(comboBox_Radix.SelectionBoxItem.ToString());

            if (textBox_P.Text.Trim() == "" || textBox_Q.Text.Trim() == "")
            {
                MessageBox.Show("请先产生大素数", "提示", MessageBoxButton.OK);
                return;
            }

            //验证输入字符是否有问题
            bool b_p = ValidateInputString(textBox_P.Text.Trim());
            bool b_q = ValidateInputString(textBox_Q.Text.Trim());
            if (b_p == false || b_q == false)
            {
                MessageBox.Show("请检查大素数P和Q的输入：\n\t10进制时只允许字符0~9\n\t16进制时只允许0~F", "出错",
                    MessageBoxButton.OK);
                return;
            }

            //从文本框中获取大整数
            BigInteger P = new BigInteger(textBox_P.Text.Trim(), radix);
            BigInteger Q = new BigInteger(textBox_Q.Text.Trim(), radix);

            //判断是否是大素数
            if ( ! P.isProbablePrime())
            {
                MessageBox.Show("P不是素数，请检查", "出错",
                    MessageBoxButton.OK);
                return;
            }
            if (!Q.isProbablePrime())
            {
                MessageBox.Show("Q不是素数，请检查", "出错",
                    MessageBoxButton.OK);
                return;
            }



            BigInteger N = P * Q;
            BigInteger NN = (P - 1) * (Q - 1); //获取欧拉函数值

            int bits = Convert.ToInt32(textBox_Bits.Text.Trim());
            BigInteger E = NN.genCoPrime(bits, rand); // 获取公钥

            BigInteger D = E.modInverse(NN); // 模逆，获取私钥

            textBox_N.Text = N.ToString(radix);
            textBox_E.Text = E.ToString(radix);
            textBox_D.Text = D.ToString(radix);

            button_Encrypt.IsEnabled = true;
            label_EncryptTooltip.Visibility = Visibility.Hidden;

            //产生新的密钥后，把之前的结果清空，防止误导
            textBox_CipherText.Text = "";
            textBox_RePlainText.Text = "";
            button_Decrypt.IsEnabled = false;
            label_DecryptTooltip.Visibility = Visibility.Visible;

        }

        /// <summary>
        /// 加密
        /// C = P ^ E % N
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_Encrypt_Click(object sender, RoutedEventArgs e)
        {
            if (textBox_PlainText.Text.Trim() == "")
            {
                MessageBox.Show("请输入明文", "提示", MessageBoxButton.OK);
                return;
            }
            bool b_plain = ValidateInputString(textBox_PlainText.Text.Trim());
            if ( ! b_plain)
            {
                MessageBox.Show("请检查明文输入：\n\t10进制时只允许字符0~9\n\t16进制时只允许0~F", "出错",
                    MessageBoxButton.OK);
                return;                
            }
            int radix = Convert.ToInt32(comboBox_Radix.SelectionBoxItem.ToString());
            BigInteger P = new BigInteger(textBox_PlainText.Text.Trim(), radix);
            BigInteger E = new BigInteger(textBox_E.Text.Trim(), radix);
            BigInteger N = new BigInteger(textBox_N.Text.Trim(), radix);

            if (P >= N)
            {
                MessageBox.Show("明文值大于N的值，会导致加密解密失效，请检查", "提示", MessageBoxButton.OK);
                return;
            }

            BigInteger C = P.modPow(E, N);

            textBox_CipherText.Text = C.ToString(radix);

            button_Decrypt.IsEnabled = true;
            label_DecryptTooltip.Visibility = Visibility.Hidden;


        }

        /// <summary>
        /// 解密
        /// P = C ^ D % N
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_Decrypt_Click(object sender, RoutedEventArgs e)
        {
            int radix = Convert.ToInt32(comboBox_Radix.SelectionBoxItem.ToString());
            BigInteger C = new BigInteger(textBox_CipherText.Text.Trim(), radix);
            BigInteger D = new BigInteger(textBox_D.Text.Trim(), radix);
            BigInteger N = new BigInteger(textBox_N.Text.Trim(), radix);

            BigInteger P = C.modPow(D, N);

            textBox_RePlainText.Text = P.ToString(radix);
        }

        /// <summary>
        /// 切换进制
        /// </summary>
        /// <param name="textStr"></param>
        /// <param name="sourceRadix"></param>
        /// <param name="targetRadix"></param>
        /// <returns></returns>
        private string SwitchShowRadix(string textStr, int sourceRadix, int targetRadix)
        {
            if (textStr.Trim() == "")
            {
                return "";
            }
            BigInteger bi_old = new BigInteger(textStr.Trim(), sourceRadix);
            string strNew = bi_old.ToString(targetRadix);
            return strNew;
        }

        /// <summary>
        /// 进制选择下拉列表打开触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void comboBox_Radix_DropDownOpened(object sender, EventArgs e)
        {
            if (bgWorkerGenP != null)
            {
                if (bgWorkerGenP.IsBusy)
                {
                    MessageBox.Show("请等待大素数生成结束", "提示", MessageBoxButton.OK);
                    return;
                }
            }
            if (bgWorkerGenQ != null)
            {
                if (bgWorkerGenQ.IsBusy)
                {
                    MessageBox.Show("请等待大素数生成结束", "提示", MessageBoxButton.OK);
                    return;
                }
            }

            //验证输入字符是否有问题
            bool b_p = ValidateInputString(textBox_P.Text.Trim());
            bool b_q = ValidateInputString(textBox_Q.Text.Trim());
            bool b_plain = ValidateInputString(textBox_PlainText.Text.Trim());
            if ( !(b_p & b_q & b_plain))
            {
                MessageBox.Show("转换进制失败，当前进制和文本框中字符类型不匹配\n请检查：\n\t十进制时只允许字符0~9\n\t16进制时只允许0~F", "出错",
                    MessageBoxButton.OK);
                return;
            }
            else
            {
                i_currentRadix = Convert.ToInt32(comboBox_Radix.SelectionBoxItem.ToString());
            }
        }

        /// <summary>
        /// 进制选择下拉列表关闭触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void comboBox_Radix_DropDownClosed(object sender, EventArgs e)
        {
            //获取新的进制数
            int i_newRadix = Convert.ToInt32(comboBox_Radix.SelectionBoxItem.ToString());

            textBox_P.Text = SwitchShowRadix(textBox_P.Text, i_currentRadix, i_newRadix);
            textBox_Q.Text = SwitchShowRadix(textBox_Q.Text, i_currentRadix, i_newRadix);
            textBox_N.Text = SwitchShowRadix(textBox_N.Text, i_currentRadix, i_newRadix);
            textBox_E.Text = SwitchShowRadix(textBox_E.Text, i_currentRadix, i_newRadix);
            textBox_D.Text = SwitchShowRadix(textBox_D.Text, i_currentRadix, i_newRadix);
            textBox_PlainText.Text = SwitchShowRadix(textBox_PlainText.Text, i_currentRadix, i_newRadix);
            textBox_CipherText.Text = SwitchShowRadix(textBox_CipherText.Text, i_currentRadix, i_newRadix);
            textBox_RePlainText.Text = SwitchShowRadix(textBox_RePlainText.Text, i_currentRadix, i_newRadix);
        }

        /// <summary>
        /// 随机产生明文
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_GeneratePlain_Click(object sender, RoutedEventArgs e)
        {
            int bits = Convert.ToInt32(textBox_Bits.Text.Trim());
            BigInteger bi = BigInteger.genPseudoPrime(bits, 0, rand);

            int radix = Convert.ToInt32(comboBox_Radix.SelectionBoxItem.ToString());
            textBox_PlainText.Text = bi.ToString(radix);

        }

        /// <summary>
        /// 明文输入框发生改变的事件，如果发生改变，则清空下面的旧的密文信息，防止误导
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBox_PlainText_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (textBox_CipherText != null)
            {
                textBox_CipherText.Text = "";
            }
            if (textBox_RePlainText != null)
            {
                textBox_RePlainText.Text = "";
            }

            if (button_Decrypt != null)
            {
                button_Decrypt.IsEnabled = false; 
            }
            if (label_DecryptTooltip != null)
            {
                label_DecryptTooltip.Visibility = Visibility.Visible;

            }
        }

        /// <summary>
        /// 从文件中读取内容
        /// </summary>
        /// <returns></returns>
        private string ReadStringFromFile()
        {
            string str_Res = "";
            OpenFileDialog openFile = new OpenFileDialog();
            openFile.Filter = "txt file(*.txt)|*.txt|All files(*.*)|*.*";
            openFile.Title = "从文件中导入大素数";

            if (openFile.ShowDialog() == true)
            {
                StreamReader sr = new StreamReader(openFile.FileName, Encoding.UTF8);
                try
                {
                    str_Res = sr.ReadToEnd();
                }
                finally
                {
                    sr.Close();
                }
            }
            else
            {
                str_Res = "";
            }
            return str_Res;
        }

        /// <summary>
        /// 从文件中导入素数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_ImportP_Click(object sender, RoutedEventArgs e)
        {
            if (bgWorkerGenP != null)
            {
                if (bgWorkerGenP.IsBusy)
                {
                    MessageBox.Show("后台正在生成素数，请等待生成操作完成", "提示", MessageBoxButton.OK);
                    return;
                }
            }

            string str_Text = ReadStringFromFile();
            if (str_Text != "")
            {
                textBox_P.Text = str_Text.Trim();
            }
        }

        private void button_ImportQ_Click(object sender, RoutedEventArgs e)
        {
            if (bgWorkerGenQ != null)
            {
                if (bgWorkerGenQ.IsBusy)
                {
                    MessageBox.Show("后台正在生成素数，请等待生成操作完成", "提示", MessageBoxButton.OK);
                    return;
                }
            }

            string str_Text = ReadStringFromFile();
            if (str_Text != "")
            {
                textBox_Q.Text = str_Text.Trim();
            }
        }

        /// <summary>
        /// 将大素数写入文件
        /// </summary>
        /// <param name="str"></param>
        private void WriteStringToFile(string str)
        {
            SaveFileDialog saveFile = new SaveFileDialog();
            saveFile.Filter = "Txt file(*.txt)|*.txt|All files(*.*)|*.*";
            saveFile.Title = "导出大素数到文件";


            if (saveFile.ShowDialog() == true)
            {
                StreamWriter sw = new StreamWriter(saveFile.FileName, false, Encoding.UTF8);
                try
                {
                    sw.Write(str);
                }
                catch (IOException ioe)
                {
                    MessageBox.Show("文件写入失败，请检查是否有权限\n" + ioe.Message, "提示", MessageBoxButton.OK);
                }
                finally
                {
                    sw.Close();
                }
            }
            else
            {
                str = "";
            }


        }

        /// <summary>
        /// 导出素数到文件中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_ExportP_Click(object sender, RoutedEventArgs e)
        {
            if (bgWorkerGenP != null)
            {
                if (bgWorkerGenP.IsBusy)
                {
                    MessageBox.Show("后台正在生成素数，请等待生成操作完成", "提示", MessageBoxButton.OK);
                    return;
                }
            }

            string text_String = textBox_P.Text.Trim();
            WriteStringToFile(text_String);
        }


        private void button_ExportQ_Click(object sender, RoutedEventArgs e)
        {
            if (bgWorkerGenQ != null)
            {
                if (bgWorkerGenQ.IsBusy)
                {
                    MessageBox.Show("后台正在生成素数，请等待生成操作完成", "提示", MessageBoxButton.OK);
                    return;
                }
            }

            string text_String = textBox_Q.Text.Trim();
            WriteStringToFile(text_String);
        }

        private void label_Info_MouseEnter(object sender, MouseEventArgs e)
        {
            label_Info.Content = "计科07-2 李巧 2007221104210523";
        }

        private void label_Info_MouseLeave(object sender, MouseEventArgs e)
        {
            label_Info.Content = "学号：2007221104210523";
        }



    }


    /// <summary>
    /// 用作BackgroundWorker的参数传递
    /// </summary>
    public partial class WorkerArgs
    {
        private int m_bits; //大素数bit位数
        private int m_radix; //进制

        public WorkerArgs()
        {
            m_bits = 300;
            m_radix = 10;
        }
        public WorkerArgs(int bits, int radix)
        {
            m_bits = bits;
            m_radix = radix;
        }

        public int Bits
        {
            get
            {
                return m_bits;
            }
            set
            {
                m_bits = value;
            }
        }

        public int Radix
        {
            get
            {
                return m_radix;
            }
            set
            {
                m_radix = value;
            }
        }
    }

}
